package com.syh.jn.scm.infrastructure.repository.impl.downstream.finance;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.syh.core.ddd.infrastructure.repository.AbstractAggregateRepository;
import com.syh.jn.scm.domain.downstream.entity.finance.DownStatementAccountBill;
import com.syh.jn.scm.domain.downstream.entity.finance.DownStatementAccountBillItem;
import com.syh.jn.scm.domain.downstream.repository.finance.DownStatementAccountBillRepository;
import com.syh.jn.scm.dto.downstream.finance.DownStatementAccountBillItemVo;
import com.syh.jn.scm.dto.downstream.finance.DownStatementAccountBillVo;
import com.syh.jn.scm.dto.upstream.finance.UpStatementAccountBillItemVo;
import com.syh.jn.scm.infrastructure.repository.model.finance.StatementAccountBillItemModel;
import com.syh.jn.scm.infrastructure.repository.model.finance.StatementAccountBillModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import org.apache.ibatis.jdbc.SQL;
import org.hibernate.Query;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Date:2018/7/20
 * Author:Clown
 * Desc;
 */
@Repository
public class DownStatementAccountBillRepositoryImpl extends AbstractAggregateRepository<DownStatementAccountBill, StatementAccountBillModel, Long> implements DownStatementAccountBillRepository {

  @Override
  public Long add(DownStatementAccountBill downStatementAccountBill) {
    Long billId = super.add(downStatementAccountBill);
    downStatementAccountBill.setId(billId);
    this.saveItems(downStatementAccountBill);

    return billId;
  }

  @Override
  public void update(DownStatementAccountBill bill) {
    super.update(bill);
    if (bill.getDownStatementAccountBillItems() != null) {
      this.removeItemByBillId(bill.getId());
      this.saveItems(bill);
    }
  }

  @Override
  public DownStatementAccountBill getById(Long aLong) {
    DownStatementAccountBill accountBill = super.getById(aLong);

    if (accountBill == null) {
      return accountBill;
    }
    List<StatementAccountBillItemModel> itemModels = (List<StatementAccountBillItemModel>) this.hibernateTemplate.
            find("from StatementAccountBillItemModel model where model.statementAccountBillId = ?", aLong);
    List<DownStatementAccountBillItem> billItems = new ArrayList<>();
    itemModels.forEach(itemModel -> {
      billItems.add(ExtBeanUtils.copyProperties(itemModel, new DownStatementAccountBillItem(), true));
    });
    accountBill.setDownStatementAccountBillItems(billItems);
    return accountBill;
  }

  private void saveItems(DownStatementAccountBill bill) {
    bill.getDownStatementAccountBillItems().forEach(billItem -> {
      StatementAccountBillItemModel itemModel = new StatementAccountBillItemModel();
      ExtBeanUtils.copyProperties(billItem, itemModel);
      itemModel.setStatementAccountBillId(bill.getId());
      itemModel.setBusinessEntityId(bill.getBusinessEntityId());
      super.hibernateTemplate.save(itemModel);
    });
  }

  @Override
  public void removeById(Long aLong) {
    this.removeItemByBillId(aLong);
    super.removeById(aLong);
  }

  @Override
  public void remove(DownStatementAccountBill downStatementAccountBill) {
    this.removeItemByBillId(downStatementAccountBill.getId());
    super.remove(downStatementAccountBill);
  }

  private void removeItemByBillId(Long billId) {
    String hql = "delete StatementAccountBillItemModel model where model.statementAccountBillId = :statementAccountBillId";
    Query query = super.buildQuery(hql);
    query.setParameter("statementAccountBillId", billId);
    query.executeUpdate();
  }

  /**
   * 上传单据图片
   *
   * @param bill
   */
  @Override
  public void upload(DownStatementAccountBill bill) {
    super.update(bill);
  }

  @Override
  protected SQL getViewSql() {
    return new SQL() {{
      SELECT(SQLAliasGenerateUtil.aliasGenerate(StatementAccountBillModel.class, "statementBill", null),
              "supplier.ID AS businessEntityId",
              "supplier.NAME AS businessEntityName");
      FROM("T_FINANCE_STATEMENT_ACCOUNT_BILL AS statementBill");
      LEFT_OUTER_JOIN("T_BASE_SUPPLIER AS supplier ON statementBill.BUSINESS_ENTITY_ID = supplier.ID");
      LEFT_OUTER_JOIN("(" +
              " SELECT GROUP_CONCAT(SOURCE_CODE) AS sourceCode, " +
              " STATEMENT_ACCOUNT_BILL_ID AS billId"  +
              " FROM " +
              " T_FINANCE_STATEMENT_ACCOUNT_BILL_ITEM " +
              " GROUP BY STATEMENT_ACCOUNT_BILL_ID " +
              " )statementItem ON statementItem.billId = statementBill.ID ");
    }};
  }

  @Override
  protected BaseResolve getViewWrapperResolve(Wrapper wrapper) {
    Map<String, String> map = new HashMap<>();
    map.put("id", "statementBill.ID");
    map.put("code", "statementBill.CODE");
    map.put("sourceCode", "statementItem.sourceCode");
    map.put("state", "statementBill.STATE");
    map.put("ticketState", "statementBill.TICKET_STATE");
    map.put("customerType", "statementBill.CUSTOMER_TYPE");
    map.put("customerId", "statementBill.CUSTOMER_ID");
    map.put("financeState", "statementBill.FINANCE_STATE");
    map.put("businessState", "statementBill.BUSINESS_STATE");
    ResolveToSQL parse = new ResolveToSQL(wrapper, (propertyName) -> {
      return map.get(propertyName);
    });
    return parse;
  }

  @Override
  protected Class getViewObject() {
    return DownStatementAccountBillVo.class;
  }

  //sql
  private SQL getSql(Long statementId) {
    return new SQL() {{
      SELECT(
              SQLAliasGenerateUtil.aliasGenerate(StatementAccountBillItemModel.class, "item", null)
      );
      FROM("( select * from T_FINANCE_STATEMENT_ACCOUNT_BILL_ITEM WHERE (SOURCE_TYPE = 0 OR SOURCE_TYPE = 1 OR SOURCE_TYPE = 2 OR SOURCE_TYPE = 3 OR SOURCE_TYPE = 4 OR SOURCE_TYPE = 5)) item");
      LEFT_OUTER_JOIN("T_FINANCE_COST_BILL cost on cost.ID = item.SOURCE_ID");
      LEFT_OUTER_JOIN("T_FINANCE_INCOME_BILL inCome on inCome.ID = item.SOURCE_ID");
      LEFT_OUTER_JOIN("T_PUR_PURCHASE_ORDER pur on pur.ID = item.SOURCE_ID");
      LEFT_OUTER_JOIN("T_SALE_ORDER sale on sale.ID = item.SOURCE_ID");
      LEFT_OUTER_JOIN("T_PUR_PURCHASE_RETURN_ORDER purRet on purRet.ID = item.SOURCE_ID");
      LEFT_OUTER_JOIN("T_SALE_RETURN_ORDER saleRet on saleRet.ID = item.SOURCE_ID");
      WHERE("item.STATEMENT_ACCOUNT_BILL_ID = " + statementId);
    }};
  }

  /**
   * 根据对账单id获取明细
   *
   * @param statementId 对账单id
   * @return
   */
  @Override
  public List<DownStatementAccountBillItemVo> getItemsByStatementId(Long statementId) {
    List<Map<String, Object>> list = MybatisTemplate.selectList(this.getSql(statementId).toString());
    List<DownStatementAccountBillItemVo> downStatementAccountBillItemVos = JSONArray.parseArray(JSONObject.toJSONString(list), DownStatementAccountBillItemVo.class);
    return downStatementAccountBillItemVos;
  }
}
